/*
 *
 *      Author: Jerome RD Soine and Christoph A Brand
 *      Institution: Schwarz goup, Institute for Theoretical Physics, Heidelberg University, Germany
 */

#include "../../../../../include/base/cell_models/ACM/geometry/geomobject.h"
#include "../../../../../include/base/cell_models/ACM/geometry/base/vertex.h"
#include "../../../../../include/base/cell_models/ACM/geometry/util/filemanager.h"

#include <string>
#include <iostream>

using namespace std;

GeomObject::~GeomObject(){
	delete fm;
	for(unsigned int i=0; i<vertices.size(); i++){
		delete vertices[i];
	}
	for(unsigned int i=0; i<triangles.size(); i++){
		delete triangles[i];
	}
	for(unsigned int i=0; i<edges.size(); i++){
		delete edges[i];
	}
}



GeomObject::GeomObject(string filename, string snapshotPath, Vertex CENTER) {
	init(filename, snapshotPath,CENTER,true);
}
GeomObject::GeomObject(string filename, string snapshotPath, Vertex CENTER, bool clear) {
	init(filename, snapshotPath,CENTER,clear);
}

void GeomObject::init(string filename, string snapshotPath, Vertex CENTER, bool clear){
	center = CENTER;
	fm = new FileManager(this, snapshotPath, clear);
	fm->load(filename);
	orientNormals();
	indexVertices();
	removeVerticesWithoutConnection();
}

void GeomObject::setColorDataExtractor(ColorDataExtractor * cde){
	fm->setColorDataExtractor(cde);
}
void GeomObject::setFixedPointsExtractor(FixedPointsExtractor * fpe){
	fm->setFixedPointsExtractor(fpe);
}

void GeomObject::indexVertices(){
	for(unsigned int i=0; i<vertices.size(); i++){
		vertices[i]->setIndex(i);
	}
	for(unsigned int i=0; i<edges.size();i++){
		edges[i]->setIndex(i);
	}
}

void GeomObject::orientNormals(){
	for(unsigned int i=0; i<triangles.size();i++){
		vector<Vertex*>* tips = triangles[i]->getTips();
		Vertex * tip0 = (*tips)[0], * tip1 = (*tips)[1], * tip2 = (*tips)[2];


		Vertex cross=(*tip1 - *tip0).cross( (*tip2 - *tip1));
		Vertex fromCenter = *tip1 - center;
		if(cross*fromCenter>0) {
			// Vertices oriented correctly
		} else {
			//Change Order
			tips->clear();
			tips->push_back(tip1);
			tips->push_back(tip0);
			tips->push_back(tip2);
		}
	}
}

void GeomObject::removeVerticesWithoutConnection(){
	vector<Vertex*> newList;
	for(unsigned int i=0; i<vertices.size(); i++){
		if(vertices[i]->getTrianglesContainingVertex()->size() > 0) {
			newList.push_back(vertices[i]);
		} else if(vertices[i]->getEdgesConnectingVertex()->size() > 0)
			newList.push_back(vertices[i]);
		else {
			delete vertices[i];
		}
	}
	vertices = newList;
}

void GeomObject::saveSnapshot(){
	fm->saveSnapshot();
}

void GeomObject::saveVTK(string filename){
	fm->save(filename);
}


void GeomObject::saveWireframe(string filename){
	fm->saveLines(filename);
}

void GeomObject::printStatus() {
	cout << endl << "------------ STATUS -------------" << endl;
	cout << "#triangles " << triangles.size() << endl;
	cout << "#edges " << edges.size() << endl;
	cout << "#vertices " << vertices.size() << endl;
	cout << "-------------------------------" << endl;
}

void GeomObject::moveVerticesBy(vector<double> & shift){
	for(unsigned int i=0; i<vertices.size();i++){
		vertices[i]->setX(vertices[i]->getX() + shift[3*i+0]);
		vertices[i]->setY(vertices[i]->getY() + shift[3*i+1]);
		vertices[i]->setZ(vertices[i]->getZ() + shift[3*i+2]);
	}
}
void GeomObject::moveVerticesBackBy(vector<double> & shift){
	for(unsigned int i=0; i<vertices.size();i++){
		vertices[i]->setX(vertices[i]->getX() - shift[3*i+0]);
		vertices[i]->setY(vertices[i]->getY() - shift[3*i+1]);
		vertices[i]->setZ(vertices[i]->getZ() - shift[3*i+2]);
	}
}

double GeomObject::volume() {
	double volume = 0;
	for (unsigned int i = 0; i < triangles.size(); i++) {
		volume += triangles[i]->volumeContribution();
	}
	return volume;
}

double GeomObject::area(){
	double area = 0;
	for (unsigned int i = 0; i < triangles.size(); i++) {
		area += triangles[i]->area();
	}
	return area;
}

void GeomObject::fixFirstVertices(int number){
	for(int i=0; i<number; i++){
		vertices[i]->setFixed(true);
	}
}
